package com.mapfinal.server.service.tile;

/**
 * 包围盒
 * 
 * @author yangyong
 *
 */
public class BoundingBox {
	private double north;
	private double south;
	private double east;
	private double west;

	public BoundingBox(final int x, final int y, final int zoom, boolean tms) {
		if (tms) {
			this.north = -tile2lat(y, zoom);
			this.south = -tile2lat(y + 1, zoom);
		} else {
			this.north = tile2lat(y, zoom);
			this.south = tile2lat(y + 1, zoom);
		}
		this.west = tile2lon(x, zoom);
		this.east = tile2lon(x + 1, zoom);
	}

	public BoundingBox(double west, double east, double south, double north) {
		this.west = west;
		this.east = east;
		this.south = south;
		this.north = north;
	}

	public boolean isNull() {
		return east < west;
	}

	public void expandToInclude(double x, double y) {
		if (isNull()) {
			west = x;
			east = x;
			south = y;
			north = y;
		} else {
			if (x < west) {
				west = x;
			}
			if (x > east) {
				east = x;
			}
			if (y < south) {
				south = y;
			}
			if (y > north) {
				north = y;
			}
		}
	}

	public void expandToInclude(BoundingBox bbox) {
		if (bbox.isNull()) {
			return;
		}
		if (isNull()) {
			west = bbox.getWest();
			east = bbox.getEast();
			south = bbox.getSouth();
			north = bbox.getNorth();
		} else {
			if (bbox.west < west) {
				west = bbox.west;
			}
			if (bbox.east > east) {
				east = bbox.east;
			}
			if (bbox.south < south) {
				south = bbox.south;
			}
			if (bbox.north > north) {
				north = bbox.north;
			}
		}
	}

	@Override
	public String toString() {
		return "[ " + east + ", " + south + ", " + west + ", " + north + " ]";
	}

	/**
	 * 瓦片获得范围
	 * 
	 * @param x
	 * @param y
	 * @param zoom
	 * @return
	 */
	public static BoundingBox tile2boundingBox(final int x, final int y, final int zoom, boolean tms) {
		BoundingBox bb = new BoundingBox(x, y, zoom, tms);
		return bb;
	}
	
	public static BoundingBox tile2boundingBox(final TileParam param) {
		BoundingBox bb = new BoundingBox(param.getX(), param.getY(), param.getZ(), param.isTms());
		return bb;
	}

	/**
	 * 瓦片转换经度
	 * 
	 * @param x
	 * @param z
	 * @return
	 */
	public static double tile2lon(int x, int z) {
		return x / Math.pow(2.0, z) * 360.0 - 180;
	}

	/**
	 * 瓦片转换纬度
	 * 
	 * @param y
	 * @param z
	 * @return
	 */
	public static double tile2lat(int y, int z) {
		double n = Math.PI - (2.0 * Math.PI * y) / Math.pow(2.0, z);
		return Math.toDegrees(Math.atan(Math.sinh(n)));
	}

	public double getNorth() {
		return north;
	}

	public void setNorth(double north) {
		this.north = north;
	}

	public double getSouth() {
		return south;
	}

	public void setSouth(double south) {
		this.south = south;
	}

	public double getEast() {
		return east;
	}

	public void setEast(double east) {
		this.east = east;
	}

	public double getWest() {
		return west;
	}

	public void setWest(double west) {
		this.west = west;
	}

}